package handler

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/syndtr/goleveldb/leveldb"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"openwechat/config"
	"openwechat/logs"
	"openwechat/utils"
	"strconv"
	"strings"
	"sync"
	"time"
)

// cache 存放数据的并发安全的map
var cache sync.Map

type tokenType string

const WechatAppToken tokenType = "WECHAT_APP_TOKEN"
const WechatKfToken tokenType = "WECHAT_KF_TOKEN"

const NextCursor = "NextCursor"
const Event = "kf_msg_or_event"

type MsgContent struct {
	ToUsername   string `json:"ToUserName" xml:"ToUserName"`
	FromUsername string `json:"FromUserName" xml:"FromUserName"`
	CreateTime   uint32 `json:"CreateTime" xml:"CreateTime"`
	MsgType      string `json:"MsgType" xml:"MsgType"`
	Content      string `json:"Content" xml:"Content"`
	Msgid        uint64 `json:"MsgId" xml:"MsgId"`
	MsgDataId    string `json:"MsgDataId" xml:"MsgDataId"`
	Idx          string `json:"Idx" xml:"Idx"`
	Agentid      string `json:"AgentId" xml:"AgentId"`
	Encrypt      string `json:"Encrypt" xml:"Encrypt"`
	Event        string `json:"Event" xml:"Event"`
	Token        string `json:"Token" xml:"Token"`
	OpenKfId     string `json:"OpenKfId" xml:"OpenKfId"`
}

type chatAppMsg struct {
	ToUser  string `json:"touser"`
	ToParty string `json:"toparty"`
	ToTag   string `json:"totag"`
	MsgType string `json:"msgtype"`
	AgentID int64  `json:"agentid"`
	Text    struct {
		Content string `json:"content"`
	} `json:"text"`
	Safe                   int `json:"safe"`
	EnableIdTrans          int `json:"enable_id_trans"`
	EnableDuplicateCheck   int `json:"enable_duplicate_check"`
	DuplicateCheckInterval int `json:"duplicate_check_interval"`
}

type chatKfMsg struct {
	ToUser   string `json:"touser"`
	OpenKFid string `json:"open_kfid"`
	MsgId    string `json:"msgid"`
	MsgType  string `json:"msgtype"`
	Text     struct {
		Content string `json:"content"`
	} `json:"text"`
}

type ReqKfMessage struct {
	Cursor      string `json:"cursor"`
	Token       string `json:"token"`
	Limit       int    `json:"limit"`
	VoiceFormat int    `json:"voice_format"`
	OpenKFid    string `json:"open_kfid"`
}

type ResKfMessage struct {
	Errcode    int         `json:"errcode"`
	Errmsg     string      `json:"errmsg"`
	NextCursor string      `json:"next_cursor"`
	HasMore    int         `json:"has_more"`
	MsgList    []KfMessage `json:"msg_list"`
}

type KfMessage struct {
	MsgId          string  `json:"msgid"`
	OpenKFid       string  `json:"open_kfid"`
	ExternalUserid string  `json:"external_userid"`
	SendTime       int     `json:"send_time"`
	Origin         int     `json:"origin"`
	ServicerUserid string  `json:"servicer_userid"`
	MsgType        string  `json:"msgtype"`
	Text           Content `json:"text"`
}

type Content struct {
	Content string `json:"content"`
}

func getString(str, endstr string, start int, msg *string) int {
	end := strings.Index(str, endstr)
	*msg = str[start:end]
	return end + len(endstr)
}

// Set 缓存过期功能实现 类Redis
func set(key interface{}, value interface{}, exp time.Duration) {
	cache.Store(key, value)
	time.AfterFunc(exp, func() {
		cache.Delete(key)
	})
}

func getAccessToken(t tokenType, secret string) (string, error) {
	value, ok := cache.Load(t)
	if ok {
		return value.(string), nil
	}
	url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s", config.Config.CorpID, secret)
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	all, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	body := map[string]interface{}{}
	if err := json.Unmarshal(all, &body); err != nil {
		return "", err
	}
	accessToken := body["access_token"]
	set(t, accessToken, time.Minute*100)
	return accessToken.(string), nil
}

func sendAppMsg(msg string, toUser string) error {
	token, err := getAccessToken(WechatAppToken, config.Config.CorpSecret)
	if err != nil {
		return fmt.Errorf("sendAppMsg getAccessToken error,e=%s", err.Error())
	}
	url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s", token)
	body := chatAppMsg{
		ToUser:  toUser,
		ToParty: "@all",
		ToTag:   "@all",
		MsgType: "text",
		AgentID: config.Config.AgentID,
		Text: struct {
			Content string `json:"content"`
		}{
			Content: msg,
		},
		Safe:                   0,
		EnableIdTrans:          0,
		EnableDuplicateCheck:   0,
		DuplicateCheckInterval: 1800,
	}
	marshal, err := json.Marshal(body)
	if err != nil {
		return err
	}
	res, err := http.Post(url, "application/json;charset=utf-8", bytes.NewReader(marshal))
	if err != nil {
		return fmt.Errorf("sendMsg Post error,e=%s", err.Error())
	}
	all, err := io.ReadAll(res.Body)
	if err != nil {
		logs.Error(string(all))
		return fmt.Errorf("sendMsg ReadAll error,e=%s", err.Error())
	}
	return nil
}

func getKfMessage(content MsgContent) ([]KfMessage, error) {
	token, err := getAccessToken(WechatKfToken, config.Config.KfSecret)
	if err != nil {
		return nil, fmt.Errorf("sendMsg getAccessToken error,e=%s", err.Error())
	}
	url := fmt.Sprintf(

		"https://qyapi.weixin.qq.com/cgi-bin/kf/sync_msg?access_token=%s", token)
	body := ReqKfMessage{
		Token:       content.Token,
		Limit:       0,
		VoiceFormat: 0,
		OpenKFid:    content.OpenKfId,
	}
	value, err := config.DB.Get([]byte(NextCursor), nil)
	if err != nil && err != leveldb.ErrNotFound {
		return nil, err
	}
	body.Cursor = string(value)
	marshal, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}
	res, err := http.Post(url, "application/json;charset=utf-8", bytes.NewReader(marshal))
	if err != nil {
		return nil, fmt.Errorf("getKfMessage Post error,e=%s", err.Error())
	}
	all, err := io.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("getKfMessage ReadAll error,e=%s", err.Error())
	}
	msgRes := new(ResKfMessage)
	if err := json.Unmarshal(all, &msgRes); err != nil {
		return nil, err
	}
	if err = config.DB.Put([]byte(NextCursor), []byte(msgRes.NextCursor), nil); err != nil {
		return nil, err
	}
	jq, err := utils.NewJsonQ(msgRes.MsgList)
	if err != nil {
		return nil, err
	}
	m := make(map[string][]KfMessage)
	if err = jq.WhereEq("msgtype", "text").Order(map[string]string{"send_time": "desc"}).GroupBy("external_userid").Find(&m); err != nil {
		logs.Error(err.Error())
		return nil, err
	}
	qusMessages := make([]KfMessage, 0)
	for k, v := range m {
		val, err := config.DB.Get([]byte("last-ask-"+k), nil)
		if err != nil && err != leveldb.ErrNotFound {
			logs.Error(err.Error())
			continue
		}
		lastTime, _ := strconv.Atoi(string(val))
		if lastTime >= v[0].SendTime {
			continue
		}
		err = config.DB.Put([]byte("last-ask-"+k), []byte(strconv.Itoa(v[0].SendTime)), nil)
		if err != nil {
			logs.Error(err.Error())
			continue
		}
		qusMessages = append(qusMessages, v[0])
	}
	return qusMessages, nil
}

func sendKfMsg(msg string, toUser, kFid, msgId string) error {
	token, err := getAccessToken(WechatKfToken, config.Config.KfSecret)
	if err != nil {
		return fmt.Errorf("sendKfMsg getAccessToken error,e=%s", err.Error())
	}
	url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=%s", token)
	body := chatKfMsg{
		ToUser:   toUser,
		OpenKFid: kFid,
		MsgId:    toUser[0:10] + string(RandUp(22)),
		MsgType:  "text",
		Text: struct {
			Content string `json:"content"`
		}{
			Content: msg,
		},
	}
	marshal, err := json.Marshal(body)
	if err != nil {
		return err
	}
	res, err := http.Post(url, "application/json;charset=utf-8", bytes.NewReader(marshal))
	if err != nil {
		return fmt.Errorf("sendMsg Post error,e=%s", err.Error())
	}
	all, err := io.ReadAll(res.Body)
	if err != nil {
		logs.Error(string(all))
		return fmt.Errorf("sendMsg ReadAll error,e=%s", err.Error())
	}
	logs.Info(string(all))
	return nil
}

// RandUp 随机字符串，包含 英文字母和数字附加=_两个符号
func RandUp(n int) []byte {
	var longLetters = []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-")
	if n <= 0 {
		return []byte{}
	}
	b := make([]byte, n)
	arc := uint8(0)
	if _, err := rand.Read(b[:]); err != nil {
		return []byte{}
	}
	for i, x := range b {
		arc = x & 63
		b[i] = longLetters[arc]
	}
	return b
}
